package dev

import (
	"fmt"
	"github.com/spf13/viper"
	"gorm.io/gorm"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"
)

type TrafficMonitor struct {
	tcpPort     int
	udpPort     int
	incomingTCP int
	incomingUDP int
	mutex       sync.Mutex
	stopChan    chan struct{}
	ticker      *time.Ticker
	userConfig  *UserConfig
}

// NewTrafficMonitor 创建一个新的流量监控器实例
func NewTrafficMonitor(tcpPort, udpPort int) *TrafficMonitor {
	return &TrafficMonitor{
		tcpPort:  tcpPort,
		udpPort:  udpPort,
		stopChan: make(chan struct{}),
		ticker:   time.NewTicker(time.Second * 5),
	}
}

// Start 启动流量监控
func (tm *TrafficMonitor) Start(userConfig *UserConfig, db *gorm.DB) {
	go tm.monitorTraffic(userConfig, db)
}

// monitorTraffic 持续监控流量
func (tm *TrafficMonitor) monitorTraffic(userConfig *UserConfig, db *gorm.DB) {
	for {
		select {
		case <-tm.stopChan:
			return
		default:
			// 使用 ss 工具监控 TCP 和 UDP 流量
			tcpCmd := exec.Command("ss", "-tn", "sport", "=", fmt.Sprintf(":%d", tm.tcpPort))
			udpCmd := exec.Command("ss", "-un", "sport", "=", fmt.Sprintf(":%d", tm.udpPort))

			tcpOutput, err := tcpCmd.CombinedOutput()
			if err != nil {
				fmt.Println("Error running ss command for TCP:", err)
				continue
			}

			udpOutput, err := udpCmd.CombinedOutput()
			if err != nil {
				fmt.Println("Error running ss command for UDP:", err)
				continue
			}

			tcpBytes := countBytes(tcpOutput)
			udpBytes := countBytes(udpOutput)

			//log.Println("打印tcp流量", tcpBytes, "打印udp流量", udpBytes)
			if tcpBytes != 0 || udpBytes != 0 {
				tm.mutex.Lock()
				tm.incomingTCP = tcpBytes
				tm.incomingUDP = udpBytes
				userConfig.Used += int64(tm.incomingTCP) + int64(tm.incomingUDP)
				err := updateUser(db, userConfig)
				if err != nil {
					fmt.Println("Error updating user:", err)
				} else {
					log.Println("流量更新成功")
				}
				log.Println(userConfig.ServerPort, "打印Quota", userConfig.Quota)
				//过期或者流量超标
				if userConfig.Used >= userConfig.Quota || userConfig.ExpiryDate.Before(time.Now()) {
					log.Println("断开端口连接")
					err := BlockPort(userConfig.ServerPort)
					if err != nil {
						return
					}
				}
				tm.mutex.Unlock()
			}

			time.Sleep(time.Second) // 调整频率根据需要
		}
	}
}

// countBytes 计算流量（假设每行的字节数信息在某列）
func countBytes(output []byte) int {
	lines := strings.Split(string(output), "\n")
	//log.Println("捕获lines", lines)
	var totalBytes int
	//log.Println("打印lines", lines)
	for _, line := range lines {
		if len(line) > 0 {
			// 这里假设字节数信息在输出的最后一列，根据实际输出调整
			fields := strings.Fields(line)
			if len(fields) > 2 {
				if recvQ, err := strconv.Atoi(fields[1]); err == nil {
					totalBytes += recvQ
				}
			}
		}
	}
	return totalBytes
}

// Stop 停止流量监控
func (tm *TrafficMonitor) Stop() {
	close(tm.stopChan)
	tm.ticker.Stop()
}

// BlockPort 阻止指定端口的流量
func BlockPort(port int) error {
	cmd := exec.Command("iptables-legacy", "-A", "INPUT", "-p", "tcp", "--dport", fmt.Sprintf("%d", port), "-j", "DROP")
	err := cmd.Run()
	if err != nil {
		return fmt.Errorf("failed to block TCP port %d: %v", port, err)
	}

	cmd = exec.Command("iptables", "-A", "INPUT", "-p", "udp", "--dport", fmt.Sprintf("%d", port), "-j", "DROP")
	err = cmd.Run()
	if err != nil {
		return fmt.Errorf("failed to block UDP port %d: %v", port, err)
	}

	return nil
}

// UnblockPort 解除指定端口的阻断
func UnblockPort(port int) error {
	cmd := exec.Command("iptables", "-D", "INPUT", "-p", "tcp", "--dport", fmt.Sprintf("%d", port), "-j", "DROP")
	err := cmd.Run()
	if err != nil {
		return fmt.Errorf("failed to unblock TCP port %d: %v", port, err)
	}

	cmd = exec.Command("iptables", "-D", "INPUT", "-p", "udp", "--dport", fmt.Sprintf("%d", port), "-j", "DROP")
	err = cmd.Run()
	if err != nil {
		return fmt.Errorf("failed to unblock UDP port %d: %v", port, err)
	}

	return nil
}

// 保存所有的 TrafficMonitor 实例
var trafficMonitors []*TrafficMonitor

func Fun(db *gorm.DB) {
	var userConfigs []UserConfig
	db.Find(&userConfigs)

	log.Println("打印数据库的userconfig", userConfigs)
	for key := range userConfigs {
		// 创建一个新的 userConfig 实例，避免引用同一个内存地址
		userConfig := userConfigs[key]

		tcpPort := userConfig.ServerPort
		udpPort := userConfig.ServerPort

		tm := NewTrafficMonitor(tcpPort, udpPort)
		if tm == nil {
			log.Fatalln("实例化流量监控失败")
			return
		}

		trafficMonitors = append(trafficMonitors, tm)
		tm.Start(&userConfig, db) // 每次迭代传递不同的 userConfig 实例
		fmt.Printf("Monitoring traffic on TCP port %d and UDP port %d\n", tcpPort, udpPort)
	}

	// 确保程序退出时停止流量监控
	//defer func() {
	//	for _, tm := range trafficMonitors {
	//		log.Fatalln("监控程序已经退出")
	//		tm.Stop()
	//	}
	//}()
}

// SyncDBAndService 同步服务器与数据库文件
func SyncDBAndService(db *gorm.DB) {
	// 读取系统文件
	dir := viper.GetString("shadowsocks.dir")
	shadowsocksConfigs, err := os.ReadDir(dir)
	if err != nil {
		return
	}

	var shadowsocksConfigNames []string
	// 遍历文件并匹配 config_*.json
	for _, file := range shadowsocksConfigs {
		// 检查文件是否以 config_ 开头并且以 .json 结尾
		if strings.HasPrefix(file.Name(), "config_") && strings.HasSuffix(file.Name(), ".json") {
			filePath := filepath.Join(dir, file.Name())
			fmt.Printf("找到配置文件: %s\n", filePath)
			shadowsocksConfigNames = append(shadowsocksConfigNames, filePath)
		}
	}
	// 读取数据库用户信息
	users, err := GetAllUser(db)
	for _, v := range users {
		log.Println("打印出数据库中用户名信息", v.Username)
		// 数据同步

	}
	// 重启服务器  todo 这个可以改为只更新单个的ss-service这样对其他用户体验更好不会影响其他人
	RestartShadowsocks()
}
